#pragma once
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <ctime>
#include <sys/wait.h>
#include "Task.hpp"
// 先描述 \0是一个字符它对应的ASII码为0
const int gdefault_process_num = 5;
typedef std::function<void(int fd)> func_t;
struct Channel
{
public:
    Channel() {}
    Channel(int fd, const std::string name, pid_t id) : _wfd(fd), _name(name), _sub_target(id) {};
    ~Channel() {}
    int Fd() { return _wfd; }
    std::string Name() { return _name; }
    pid_t Target() { return _sub_target; }
    void Close() { close(_wfd); }
    void Wait()
    {
        int rid = waitpid(_sub_target, nullptr, 0);
        (void)rid;
    }

private:
    int _wfd;          // 写端的文件描述符
    std::string _name; // 目标子进程的名字
    pid_t _sub_target; // 目标子进程的pid
};
class ProcessPool
{
private:
    void CtrlSubProcessHelper(int &index)
    {
        // 1. 选择一个通道(进程)
        int who = index;
        index++;
        index %= _channels.size();
        int x = rand() % tasks.size(); // [0, 3]
        // 3. 任务推送给子进程
        std::cout << "选择信道: " << _channels[who].Name() << ", subtarget : " << _channels[who].Target() << std::endl;
        write(_channels[who].Fd(), &x, sizeof(x));
        sleep(1);
    }

public:
    ProcessPool(int num = gdefault_process_num)
        : _processnum(num)
    {
    }

    ~ProcessPool()
    {
    }
    bool InitProcessPool(func_t cb)
    {
        for (int i = 0; i < _processnum; i++)
        {
            // 1.创建了管道
            int pipefd[2] = {0};
            int n = pipe(pipefd); // 成功—>返回0 失败返回—> -1并且设置错误码
            // pipefd[0]->保存的是读的文件描述符 pipefd[1]->保存的是写的文件描述符
            if (n < 0)
            {
                return false;
            }
            // 创建子进程
            pid_t id = fork();
            if (id < 0)
                return false;
            if (id == 0)
            {
                // 这是子进程 关闭写端
                close(pipefd[1]);

                // 子进程完成自己的任务
                cb(pipefd[0]);
            }
            // 父进程关闭读端
            close(pipefd[0]);
            std::string name = "channel" + std::to_string(i);
            _channels.emplace_back(pipefd[1], name, id);
        }
        return true;
    }
    void PollingCtrlSubProcess(int num)
    {
        if (num < 0)
            return;
        int index = 0;
        while (num)
        {
            CtrlSubProcessHelper(index);
            num--;
        }
    }
    void WaitSubProcesses()
    {
        for (auto &c : _channels)
        {
            c.Close();
        }
        for (auto &c : _channels)
        {
            c.Wait();
        }
    }

private:
    std::vector<Channel> _channels; // 所有信道
    int _processnum;                // 有多少个子进程
};
